package com.lecture.junit.tdd.example.state;


import com.lecture.junit.tdd.example.IAccount;
import com.lecture.junit.tdd.example.LoginServiceInterface;
import com.lecture.junit.tdd.example.exception.*;
import org.joda.time.DateTime;

import java.util.concurrent.atomic.AtomicInteger;

public abstract class LoginServiceState {

    AtomicInteger count;

    public void login(LoginServiceInterface context, IAccount acc, String password) throws AccountException {
        if (acc.passwordMatches(password)) {
            if (acc.isLoggedIn()) {
                throw new AccountAlreadyLoggedInException();
            }
            if (acc.isRevoked()) {
                throw new AccountIsRevokedException();
            }

            if (acc.isPasswordExpired()) {
                throw new PasswordExpiredException();
            }

            DateTime lastDateTime = acc.getLastTimeChangePassword();
            if (lastDateTime.compareTo(acc.getLastTimeLoggedIn()) > 0) {
                lastDateTime = acc.getLastTimeLoggedIn();
            }
            if (lastDateTime.compareTo(acc.getLastTimeLoggedOut()) > 0) {
                lastDateTime = acc.getLastTimeLoggedOut();
            }
            if (lastDateTime.plusDays(context.getDayLifeAccount()).compareTo(DateTime.now()) <= 0) {
                acc.setRevoked();
                throw new AccountIsRevokedException();
            }

            if (acc.getLastTimeChangePassword().plusDays(context.getDayLifePassword()).compareTo(DateTime.now()) <= 0) {
                acc.setPasswordExpired();
                throw new PasswordExpiredException();
            }

            acc.setLoggedIn();
            acc.updateLastTimeLoggedIn();
            context.setState(acc.getUserName(), new AwaitFirstLoginAttempt());
        } else {
            handlePasswordFail(context, acc);
        }
    }

    public void changePassword(LoginServiceInterface context, IAccount acc, String password, String newPassword) throws AccountException {
        if (acc.passwordMatches(password)) {
            if (acc.isRevoked()) {
                throw new AccountIsRevokedException();
            }

            DateTime lastDateTime = acc.getLastTimeChangePassword();
            if (lastDateTime.compareTo(acc.getLastTimeLoggedIn()) > 0) {
                lastDateTime = acc.getLastTimeLoggedIn();
            }
            if (lastDateTime.compareTo(acc.getLastTimeLoggedOut()) > 0) {
                lastDateTime = acc.getLastTimeLoggedOut();
            }
            if (lastDateTime.plusDays(context.getDayLifeAccount()).compareTo(DateTime.now()) <= 0) {
                acc.setRevoked();
                throw new AccountIsRevokedException();
            }

            if (acc.isOldPassword(newPassword)) {
                throw new InvalidPasswordException();
            }

            acc.changePassword(password, newPassword);
            acc.resetPasswordExpided();
            acc.updateLastTimeChangePassword();
            context.setState(acc.getUserName(), new AwaitFirstLoginAttempt());
        } else {
            handlePasswordFail(context, acc);
        }
    }

    protected abstract void handlePasswordFail(LoginServiceInterface context, IAccount acc);

}
